性能优化--webpack初探

概念

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

模块化

大家在接触到webpack的时候,可能并不知道它有什么用处,只知道它必不可缺而且听着很复杂。那到底为什么要使用它呢?首先需要了解模块化。

1
2
3
4
5
6
7
8
9
10
11
代码一
<script src="jquery.js"></script>
  <script src="jquery_scroller.js"></script>
  <script src="main.js"></script>
  <script src="other1.js"></script>
  <script src="other2.js"></script>
  <script src="other3.js"></script>
代码二
var id = ''
....
var id = ''

无模块化缺点很明显:

  • 代码可读性差难以维护
  • 全局变量重复几率大大增加,因为代码都在一个作用域中
  • 依赖关系混乱,js代码从上到下执行,因此需要弄清楚js之间的引入依赖关系
    ……

随着web的发展,简单的网页已经不满足用户需求,代码也随之越来越复杂,在大牛的推动下,js的第一个模块化规范出现了

commonJs(服务端模块化)
Nodejs出现开创了一个新的纪元,使得我们可以使用javascript写服务器代码,对于服务端而言必然是需要模块化的。CommonJS对模块的定义非常简单,主要分为模块引用,模块定义和模块标识3部分,基于node来说的,所以前面说的CommonJS都是针对服务端的实现。

  • 模块引用
1
2
3
var add = require('./add.js');
var config = require('config.js');
var http = require('http');
  • 模块定义
1
2
3
4
5
6
module.exports.add = function () {
...
}
module.exports = function () {
return ...
}
  • 模块标识

(AMD,CMD,UMD,ES6)前端模块化

  • 服务端加载一个模块,直接就从硬盘或者内存中读取了,消耗时间可以忽略不计
  • 浏览器需要从服务端下载这个文件,所以说如果用CommonJS的require方式加载模块,需要等代码模块下载完毕,并运行之后才能得到所需要的API。
  • 如果我们在某个代码模块里使用CommonJS的方法require了一个模块,而这个模块需要通过http请求从服务器去取,如果网速很慢,而CommonJS又是同步的,所以将阻塞后面代码的执行,从而阻塞浏览器渲染页面,使得页面出现假死状态。

ES6模块化

  • ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
  • ES6 模块设计思想:尽量的静态化、使得编译时就能确定模块的依赖关系,以及输入和输出的变量(CommonJS和AMD模块,都只能在运行时确定这些东西)。
  • 优点:
    容易进行静态分析
    面向未来的 EcmaScript 标准
  • 缺点:
    原生浏览器端还没有实现该标准
    全新的命令字,新版的 Node.js才支持。

require与import的区别

require使用与CommonJs规范,import使用于Es6模块规范;所以两者的区别实质是两种规范的区别;
CommonJS:

  • 对于基本数据类型,属于复制。即会被模块缓存;同时,在另一个模块可以对该模块输出的变量重新赋值。
  • 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
  • 当使用require命令加载某个模块时,就会运行整个模块的代码。
  • 当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
  • 循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出。

ES6模块

  • ES6模块中的值属于【动态只读引用】。
  • 对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
  • 对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
  • 循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。